#!/usr/bin/python
# assembler for the vrisc
# translates assembler code into machine code

import instruction_set
import sys

def cutter(line, signs, line_counter):
	semi = signs[0]
	empty = signs[1]
	# get pseudo_instruction
	try:
		x = line.split(semi)
		while('' in x): x.remove('')
		if len(x) <= 2:
			pseudo_op = x[0].strip()
			tail = x[1].strip()
		elif len(x) > 2:
			print instruction_set.error.output("in_pr_c", line_counter)
			sys.exit(0)
	except:
		tail = line.strip()
		pseudo_op = ''	
	# split tail string into instruction and operands
	try:
		x = tail.split(empty)
		while('' in x): x.remove('')
		ins = x[0].strip()
		op = x[1].strip()
	except:
		ins = tail
		op = ''
	return pseudo_op, ins, op
	

def assemble(pre_code, code):
	line_counter = 0
	instruction_set.instruction_list.extend(['DV', 'DC', 'DS'])
	instructions = instruction_set.instruction_list
	# first assembler step
	# read instructions and translate to instruction_set numbers
	while(line_counter < len(pre_code)):
		# skip empty lines or lines with a comment, signalized by: ;
		while(len(pre_code[line_counter].strip()) == 0 or pre_code[line_counter].strip()[0] == ';'):
			if line_counter < len(pre_code) - 1: line_counter = line_counter + 1
			else: line_counter = len(pre_code) - 1; break
		if len(pre_code[len(pre_code) - 1].strip()) == 0 and line_counter == len(pre_code) - 1: break
		# ignore comment in line
		line = pre_code[line_counter].strip()
		# cut off comments
		if line.find(';') >= 0:
			 line = line[:line.index(';')].strip()
		pseudo_op, ins, op = cutter(line, [':', ' '], line_counter)
		if ins in instructions:
			ins_code = instructions.index(ins)
			if ins == 'DC' or ins == 'DV':
				ins_code = op
				op = ''
			if ins == 'DS':
				for i in range(int(op) - 1): code.append('0')
				ins_code = op
				op = ''
			if len(pseudo_op) != 0: code.append(pseudo_op + ':' + str(ins_code))
			else: code.append(ins_code)
		else: print instruction_set.error.output("in_pr_c", line_counter); sys.exit(1)
		if len(op) != 0:
			for i in op.split(','):
				if i[0] == 'R': code.append(i[1:])
				else: code.append(i)
		line_counter = line_counter + 1
	# second assembler step
	# translate variables and pseudo_instructions instructions
 	for i in code:
		if str(i).find(':') >= 0:
			line = code.index(i)
			pre_line = i.split(':')[0]
			op = i.split(':')[1]
			for j in code:
				if j == pre_line:
					code[code.index(pre_line)] = line
			code[code.index(i)] = op
	return code
			

# read parameters
try:
	# program code
	program = sys.argv[1]
	output = sys.argv[2]
	# output file: binary -b or plain text -p, default plain text
	try:
		output_p = sys.argv[3]
	except:
		output_p = '-p'
except:
	print instruction_set.error.output("no_pr")

# read assembler program code
program_file = open(program, 'r')
lines = program_file.readlines()
program_file.close()
code = assemble(lines, [])

# print output to file
output_str = ""
for i in code:
	output_str = output_str + str(i) + ', '
program_file = open(output, 'w')
program_file.write(output_str[:-2] + '\n')
program_file.close()
